﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SNSpirit.Documents.Adatpers.Ubb.Internal
{
	using Snowdreamist.Collection.Tree;
	using Snowdreamist.Text.UBB;
	using Snowdreamist.Windows.Document;

	using System.Windows;
	using System.Windows.Documents;
	using System.Windows.Media;

	/// <summary>
	/// Internal class to provider UBB to rich text document conversions. This is a static class.
	/// </summary>
	internal static class UbbToRichTextService
	{
		public static RichTextDocument Convert(UBBDocument source, UbbToRichTextOptions options)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// Convert a single element.
		/// </summary>
		/// <param name="element">The element to be converting.</param>
		/// <param name="context">Conversion context.</param>
		private static void ConvertElement(this UBBElement element, ConversionContext context)
		{
			switch (element.LabelName.ToLower())
			{
				case "b":
					ApplyBoldStyle(element, context);
					break;
			}
		}

		/// <summary>
		/// Convert all sub-element of an <see cref="UBBElement"/>.
		/// </summary>
		/// <param name="element">The element.</param>
		/// <param name="context">Conversion context.</param>
		private static void ConvertSubElements(this UBBElement element, ConversionContext context)
		{
			foreach (var i in element.Children)
			{
				i.ConvertElement(context);
			}
		}

		private static void InsertList(ListElement element, ConversionContext context)
		{
			var list = new List();

			// Set list marker

			switch (element.ItemType)
			{
				case ListItemType.Default:
					// TODO: Default style option
					list.MarkerStyle = TextMarkerStyle.None;
					break;
				case ListItemType.Number:
					list.MarkerStyle = TextMarkerStyle.Decimal;
					break;
				case ListItemType.LowerCaseLetter:
					list.MarkerStyle = TextMarkerStyle.LowerLatin;
					break;
				case ListItemType.CapitalLetter:
					list.MarkerStyle = TextMarkerStyle.UpperLatin;
					break;
			}

			foreach (var i in element.Children)
			{
				var listItem = new ListItem();

				list.ListItems.Add(listItem);
			}
		}

		private static void InsertText(Snowdreamist.Text.UBB.TextElement element, ConversionContext context)
		{
			// Split all lines.
			var lines = element.Value.Split(new[] { "\r", "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

			var span = new Span();

			foreach (var i in lines)
			{
				span.Inlines.Add(i);
				span.Inlines.Add(new LineBreak());
			}
		}

		private static void InsertImage(ImageElement element, ConversionContext context)
		{
			throw new NotImplementedException();
		}

		private static void InsertCode(CodeElement target, ConversionContext context)
		{
			throw new NotImplementedException();
		}

		#region Style Elements

		private static void ApplyBoldStyle(UBBElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new BoldStyle()))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyItaticStyle(UBBElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new ItalicStyle()))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyUnderLineStyle(UBBElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new UnderLineStyle()))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyStrikeThroughStyle(UBBElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new StrikeThroughStyle()))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyFontStyle(FontElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new FontStyle(element.FontFamily)))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyColorStyle(ColorElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new ColorStyle(element.Color.ToPresentationColor())))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyFloatStyle(FloatElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new FlowDirectionStyle(element.Type.ToPresentationFlow())))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplyAlignStyle(AlignElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new AlignmentStyle(element.AlignType.ToPresentationAlignment())))
			{
				element.ConvertSubElements(context);
			}
		}

		private static void ApplySizeStyle(SizeElement element, ConversionContext context)
		{
			using (context.StyleStack.PushContext(new SizeStyle(element.Size)))
			{
				element.ConvertSubElements(context);
			}
		}

		#endregion

		/// <summary>
		/// Insert a single-line text into the 
		/// </summary>
		/// <param name="text"></param>
		private static void InsertSingleLineText(string text)
		{
		}

		#region Helper Methods

		private static TextAlignment ToPresentationAlignment(this Snowdreamist.Text.UBB.AlignType value)
		{
			switch (value)
			{
				case AlignType.Left:
					return TextAlignment.Left;
				case AlignType.Right:
					return TextAlignment.Right;
				case AlignType.Center:
					return TextAlignment.Center;
				default:
					throw new ArgumentOutOfRangeException("value");
			}
		}

		private static FlowDirection ToPresentationFlow(this Snowdreamist.Text.UBB.FloatType value)
		{
			switch (value)
			{
				case FloatType.Left:
					return FlowDirection.RightToLeft;
				case FloatType.Right:
					return FlowDirection.LeftToRight;
				default:
					throw new ArgumentOutOfRangeException("value");
			}
		}

		/// <summary>
		/// Convert a <see cref="System.Drawing.Color"/> to <see cref="System.Windows.Media.Color"/>.
		/// </summary>
		/// <param name="color">The source color.</param>
		/// <returns>The new color.</returns>
		private static Color ToPresentationColor(this System.Drawing.Color color)
		{
			return new Color
			{
				A = color.A,
				R = color.R,
				G = color.G,
				B = color.B
			};
		}

		/// <summary>
		/// take a deep-first iteration for a tree node.
		/// </summary>
		/// <typeparam name="T">Element type of the tree node.</typeparam>
		/// <param name="node">The node to execute the deep-first iteration.</param>
		/// <returns>The node sequence which in a deep-first order.</returns>
		private static IEnumerable<T> DeepFirstIter<T>(T node) where T : ITreeNode<T>
		{
			return node.Children.SelectMany(x => DeepFirstIter(x)).Concat(Enumerable.Repeat(node, 1));
		}

		#endregion
	}
}
